#include "asan_interceptors_memintrinsics.h"
#include "asan_interceptors.h"
#include "sanitizer_libc.h"
#include "asan_internal_defs.h"
#include "asan_alloctor.h"
#include "asan_report.h"

using namespace __sanitizer;

INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
  // We need to check the asan_inited here so that qemu can also work
  if (!asan_inited) return internal_memcpy(to, from, size); 
  VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__);
  // TODO: check overlap
  CheckAndReport(from, size, false);
  CheckAndReport(to, size, true);
  // return internal_memcpy(to, from, size);
  return REAL(memcpy(to, from, size));
}

INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
  if (!asan_inited) return internal_memset(block, c, size);
  VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__);
  CheckAndReport(block, size, true);
  // return internal_memset(block, c, size);
  return REAL(memset(block, c, size));
}

INTERCEPTOR(void*, memmove, void* to, const void* from, uptr size) {
  if (!asan_inited) return internal_memmove(to, from, size);
  VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__);
  CheckAndReport(from, size, false);
  CheckAndReport(to, size, true);
  // return internal_memmove(to, from, size);
  return REAL(memmove(to, from, size));
}

extern "C" {

void* __asan_memcpy(void* to, const void* from, uptr size) {
  if (!asan_inited) return internal_memcpy(to, from, size);
  // TODO: check overlap
  VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__);
  CheckAndReport(from, size, false);
  CheckAndReport(to, size, true);
  // return internal_memcpy(to, from, size);
  return REAL(memcpy(to, from, size));
}

void* __asan_memset(void* block, int c, uptr size) {
  if (!asan_inited) return internal_memset(block, c, size);
  VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__);
  CheckAndReport(block, size, true);
  // return internal_memset(block, c, size);
  return REAL(memset(block, c, size));
}

void* __asan_memmove(void* to, const void* from, uptr size) {
  if (!asan_inited) return internal_memmove(to, from, size);
  // TODO: check overlap
  VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__);
  CheckAndReport(from, size, false);
  CheckAndReport(to, size, true);
  // return internal_memmove(to, from, size);
  return REAL(memmove(to, from, size));
}

}